package com.jcxt.sys.common.code_generate;

import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.beanutils.ConvertUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Properties;

/**
 * @author 邱理
 * @description
 * @date 创建于 2019/4/20
 */
@Slf4j
public final class PropertyFileInjector {

    private final Properties properties;

    private PropertyNameMapper mapper;

    public PropertyFileInjector(ClassLoader cl, String... propertyFiles) {
        properties = new Properties();
        mapper = PropertyNameMapper.UnderLineToCamel;
        Arrays.stream(propertyFiles).forEach(p -> {
            try {
                properties.load(new InputStreamReader(cl.getResourceAsStream(p), Charset.forName("utf-8")));
            } catch (IOException e) {
                log.warn("cannot read property file: {}", p);
            }
        });
    }

    public <T> T inject(Class<T> propertyClass, String prefix) {

        T object = BeanUtils.instantiateClass(propertyClass);
        val names = properties.propertyNames();
        while (names.hasMoreElements()) {
            final String keyName = (String) names.nextElement();
            final String value = properties.getProperty(keyName);
            if (org.apache.commons.lang3.StringUtils.isBlank(value)) continue;
            ;
            String name = keyName;
            if (name.startsWith(prefix)) {
                name = name.substring(prefix.length());
                if (name.charAt(0) == '.')
                    name = name.substring(1);

                name = mapper.keyNameToClassPropertyName(name);
                val writer = ReflectionUtils.findMethod(propertyClass, "set" + StringUtils.capitalize(name), (Class<?>[]) null);
                if (writer == null || writer.getParameterTypes().length != 1) continue;
                writer.setAccessible(true);
                try {
                    writer.invoke(object, ConvertUtils.convert(value, writer.getParameterTypes()[0]));
                } catch (InvocationTargetException | IllegalAccessException e) {
                    log.warn("cannot set property {} on field: {}", keyName, writer.getName());
                }
            }
        }
        return object;
    }
}





















